热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

搜索算法-讲解[八皇后问题]

算法分析深度优先搜索法。首先我们来想象一只老鼠,在一座不见天日的迷宫内,老鼠在入口处进去,要从出口出来。那老鼠会怎么走?当然是这样的:老鼠如果遇到直路,就一直往前走,如果遇到分叉路口,就

算法分析

深度优先搜索法。
首先我们来想象一只老鼠,在一座不见天日的迷宫内,老鼠在入口处进去,要从出口出来。那老鼠会怎么走?当然是这样的:老鼠如果遇到直路,就一直往前走,如果遇到分叉路口,就任意选 择其中的一个继续往下走,如果遇到死胡同,就退回到最近的一个分叉路口,选择另一条道路再走下去,如果 遇到了出口,老鼠的旅途就算结束了。

深度优先搜索法的基本原则就是这样:按照某种条件往前试探搜索,如 果前进中遭到失败(正如老鼠遇到死胡同)则退回头另选通路继续搜索,直到找到条件的目标为止。
实现这一算法,我们要用到编程的另一大利器--递归。

再举一个例子;从前有座山,山里有座庙,庙里有个老和尚,老和尚在讲故事,讲什么呢?讲:从前有座山,山里有座庙,庙里有个老和尚,老和尚在讲故事,讲什么呢?讲:从前有座山,山里有座庙,庙里有个老和尚, 老和尚在讲故事,讲什么呢?讲:…………。好家伙,这样讲到世界末日还讲不玩,老和尚讲的故事实际上就 是前面的故事情节,这样不断地调用程序本身,就形成了递归。 万一这个故事中的某一个老和尚看这个故事不 顺眼,就把他要讲的故事换成:“你有完没完啊!”,这样,整个故事也就嘎然而止了。我们编程就要注意这 一点,在适当的时候,就必须要有一个这样的和尚挺身而出,把整个故事给停下来,或者使他不再往深一层次搜索,要不,我们的递归就会因计算机存储容量的限制而被迫溢出,切记,切记。
我们把递归思想运用到上面的迷宫中,记老鼠现在所在的位置是(x,y),那它现在有前后左右4个方向可以走,分别是(x+1,y),(x-1,y),(x,y+1),(x,y-1),其中一个方向是它来时的路,我们先不考虑,我们就分别尝试其他三个方向,如果某个方向是路而不是墙的话,老鼠就向那个方向迈出一步。在新的 位置上,我们又可以重复前面的步骤。老鼠走到了死胡同又是怎么回事?就是除了来时的路,其他3个方向都是墙,这时这条路就走到了尽头,无法再向深一层发展,我们就应该沿来时的路回去,尝试另外的方向。

例:八皇后问题:
8只皇后,使她们彼此互相都不能吃到对方,求皇后的放法。
这是一道很经典的题目了,如何运用深度优先搜索法,完成这道题目。我们先建立一个8*8格的棋盘,在棋盘的第一行的任意位置安放一只皇后。紧接着,我们就来放 第二行,第二行的安放就要受一些限制了,因为与第一行的皇后在同一竖行或同一对角线的位置上是不能安放皇后的,接下来是第三行……,或许我们会遇到这种情况,在摆到某一行的时候,无论皇后摆放在什么位置,她都会被其他行的皇后吃掉,这说明什么呢?这说明,我们前面的摆放是失败的,也就是说,按照前面的皇后的摆放方法,我们不可能得到正确的解。那这时怎么办?改啊,我们回到上一行,把原先我们摆好的皇后换另外一个位置,接着再回过头摆这一行,如果这样还不行或者上一行的皇后只有一个位置可放,那怎么办?我们回到上一行的上一行,这和老鼠碰了壁就回头是一个意思。就这样的不断的尝试,修正,尝试修正,我们最终会得到正确的结论的。

[参考程序]

program queen;{8皇后问题参考程序}
const n=8;
var a,b:array [1..n] of integer;{数组a存放解:a[i]表示第i个皇后放在第a[i]列;}
     c:array [1-n,n-1] of integer;
     d:array [2..n+n] of
integer;{数组b,c,d表示棋盘的当前情况:b[k]为1表示第k行已被占领为0表示为空;c、d表示对角线}
     k:integer;
procedure print;{打印结果}
var j:integer;
begin
           for j:=1 to n do write(a[j]:4);
           writeln;
end;
procedrue try(i:integer); {递归搜索解}
var
j:integer;{每个皇后的可放置位置。注意:一定要在过程中定义;否则当递归时会覆盖掉它的值,不能得到正确
结果}
begin
      for j:=1 to n do
      begin
           if (b[j]=0) and (c[i-j]=0) and    (d[i+j]=0) then{检查位置是否合法}
           begin
                a[i]:=j;{置第i个皇后的位置是第j行}
                b[j]:=1;{宣布占领行、对角线}
                c[i-j]:=1;
                d[i+j]:=1;
                if i<8 then try(i+1) else print;
                b[j]:=0;{清空被占行、对角线,回溯}
                c[i-j]:=0;
                d[i+j]:=0;
           end;
      end;
end;
begin
           for k:=1 to n do b[k]:=0;{初始化数据}
           for k:=1-n to n-1 do c[k]:=0;
           for k:=2 to n+n do d[k]:=0;
           try(1);
end.

N皇后问题
问题描述:
   在N*N的棋盘上,放置N个皇后,要求每一横行,每一列,每一对角线上均只能放置一个皇后,求可能的方案及方案数。

{
   Problem    : N Queens Problem
   Algorithm : Depth First Search
   Author     : tenshi
   Date       : 2002-07-14 @ SJTU ZZL 111
}
Program N_Queens;
const n=8;
var
   a:array[1..n] of integer;    { 皇后放在 ( i, a[i] ) }
   mk:array[1..n] of boolean; { 如果mk[i]为true,表示第i列可以放 }
   total:integer;              { 方案总数 }
  
   procedure output; {输出}
   var i:integer;
   begin
     inc(total);
     write('No.':4,'[',total:2,']');
     for i:=1 to n do write(a[i]:3);
     writeln;    
   end;
  
   function can(d:integer):boolean;   {判断第d行的Queen可否放在第a[d]列}
   var i:Integer;
   begin
     can:=false;
     if mk[a[d]] then exit; {如果第d列已经被占,则返回false}
     for i:=1 to d-1 do
       if abs(a[i]-a[d])=abs(i-d) then exit; { 如果第i行和第d行的Queen在同一对角线上,则返回false }
     can:=true;
   end;
  
   procedure dfs(d:integer);
   var i,j:integer;
   begin
     if (d>n) then   { 找到一个解并输出 }
     begin
       output;  
       exit;
     end;
     for i:=1 to N do    { 每一行均有N种放法 }
     begin
       a[d]:=i;           { 第d行的Queen放在第a[d]列 }
       if can(d) then
       begin
         mk[i]:=true;    { 标记第i列已经被占 }
         dfs(d+1);       { 如果第d行的方法可行,就放下一行 }
         mk[i]:=false;   { 恢复第i列被占标记 }
       end;                       
     end;
   end;
  
   begin
     fillchar(mk,sizeof(mk),0);
     dfs(1);
     writeln('Total = ',total);
   end.


                      

把N拆分为若干个数的和
问题描述:
  给定一个正整数N,假设 0为N的一个拆封。现在要求N的拆分数目。例如:当N= 6 时
6 = 1 + 1 + 1 + 1 + 1 + 1
   = 1 + 1 + 1 + 1 + 2
   = 1 + 1 + 2 + 2
   = 2 + 2 + 2
   = 1 + 1 + 1 + 3
   = 1 + 2 + 3
   = 3 + 3
   = 1 + 1 + 4
   = 2 + 4
   = 1 + 5
   = 6
  所以 6 的整数拆分个数为 11

{
   Problem    : N = A1 + A2 ... + As
   Algorithm : Depth First Search
   Author     : tenshi
   Date       : 2002-07-15 @ SJTU ZZL 111
}
Program N_Sum;
const n=6; 
var
   a:array[1..n] of integer;   { 保存单个拆分。n最多拆封为n个1,所以s<=n }
   total:integer;              { 方案总数 }
  
   procedure output(s:integer); { 输出。 s为一个拆分的长度 }
   var i:integer; 
   begin 
     write(n,' =',a[1]:3); 
     for i:=2 to s do write(' +',a[i]:3);
     writeln;    
   end; 
  
  
   procedure dfs(d,low,rest:integer);    { low为当前a[d]的下界,rest为还剩下多少要拆分 }
   var i:integer; 
   begin 
     if(rest=0) then {找到一组解}
     begin
       inc(total);
       output(d-1);
     end;
     if( low>rest ) then exit;
     {rest已经不能满足low的要求了,所以退出}
     for i:=low to rest do
     begin
       a[d]:=i;
       dfs(d+1,i,rest-i);
     end;
   end; 
  
   begin 
     dfs(1,1,n);
     writeln('Total = ',total); 
   end.


推荐阅读
  • Excel数据处理中的七个查询匹配函数详解
    本文介绍了Excel数据处理中的七个查询匹配函数,以vlookup函数为例进行了详细讲解。通过示例和语法解释,说明了vlookup函数的用法和参数的含义,帮助读者更好地理解和运用查询匹配函数进行数据处理。 ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • 也就是|小窗_卷积的特征提取与参数计算
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了卷积的特征提取与参数计算相关的知识,希望对你有一定的参考价值。Dense和Conv2D根本区别在于,Den ... [详细]
  • Go语言实现堆排序的详细教程
    本文主要介绍了Go语言实现堆排序的详细教程,包括大根堆的定义和完全二叉树的概念。通过图解和算法描述,详细介绍了堆排序的实现过程。堆排序是一种效率很高的排序算法,时间复杂度为O(nlgn)。阅读本文大约需要15分钟。 ... [详细]
  • 开发笔记:Docker 上安装启动 MySQL
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了Docker上安装启动MySQL相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 本文介绍了使用哈夫曼树实现文件压缩和解压的方法。首先对数据结构课程设计中的代码进行了分析,包括使用时间调用、常量定义和统计文件中各个字符时相关的结构体。然后讨论了哈夫曼树的实现原理和算法。最后介绍了文件压缩和解压的具体步骤,包括字符统计、构建哈夫曼树、生成编码表、编码和解码过程。通过实例演示了文件压缩和解压的效果。本文的内容对于理解哈夫曼树的实现原理和应用具有一定的参考价值。 ... [详细]
  • Learning to Paint with Model-based Deep Reinforcement Learning
    本文介绍了一种基于模型的深度强化学习方法,通过结合神经渲染器,教机器像人类画家一样进行绘画。该方法能够生成笔画的坐标点、半径、透明度、颜色值等,以生成类似于给定目标图像的绘画。文章还讨论了该方法面临的挑战,包括绘制纹理丰富的图像等。通过对比实验的结果,作者证明了基于模型的深度强化学习方法相对于基于模型的DDPG和模型无关的DDPG方法的优势。该研究对于深度强化学习在绘画领域的应用具有重要意义。 ... [详细]
  • macOS Big Sur全新设计大版本更新,10+个值得关注的新功能
    本文介绍了Apple发布的新一代操作系统macOS Big Sur,该系统采用全新的界面设计,包括图标、应用界面、程序坞和菜单栏等方面的变化。新系统还增加了通知中心、桌面小组件、强化的Safari浏览器以及隐私保护等多项功能。文章指出,macOS Big Sur的设计与iPadOS越来越接近,结合了去年iPadOS对鼠标的完善等功能。 ... [详细]
  • 本文整理了315道Python基础题目及答案,帮助读者检验学习成果。文章介绍了学习Python的途径、Python与其他编程语言的对比、解释型和编译型编程语言的简述、Python解释器的种类和特点、位和字节的关系、以及至少5个PEP8规范。对于想要检验自己学习成果的读者,这些题目将是一个不错的选择。请注意,答案在视频中,本文不提供答案。 ... [详细]
  • 深入解析Linux下的I/O多路转接epoll技术
    本文深入解析了Linux下的I/O多路转接epoll技术,介绍了select和poll函数的问题,以及epoll函数的设计和优点。同时讲解了epoll函数的使用方法,包括epoll_create和epoll_ctl两个系统调用。 ... [详细]
  • 摘要1:ElasticSearch比较两个时间的大小_gaojie_csdn的博客-CSDN博客_es时间比较摘要2:zlasticsearch脚本教 ... [详细]
  • 数据结构与算法的重要性及基本概念、存储结构和算法分析
    数据结构与算法在编程领域中的重要性不可忽视,无论从事何种岗位,都需要掌握数据结构和算法。本文介绍了数据结构与算法的基本概念、存储结构和算法分析。其中包括线性结构、树结构、图结构、栈、队列、串、查找、排序等内容。此外,还介绍了图论算法、贪婪算法、分治算法、动态规划、随机化算法和回溯算法等高级数据结构和算法。掌握这些知识对于提高编程能力、解决问题具有重要意义。 ... [详细]
  • 程序员如何选择机械键盘轴体?红轴和茶轴对比
    本文介绍了程序员如何选择机械键盘轴体,特别是红轴和茶轴的对比。同时还介绍了U盘安装Linux镜像的步骤,以及在Linux系统中安装软件的命令行操作。此外,还介绍了nodejs和npm的安装方法,以及在VSCode中安装和配置常用插件的方法。最后,还介绍了如何在GitHub上配置SSH密钥和git的基本配置。 ... [详细]
  • 2018年人工智能大数据的爆发,学Java还是Python?
    本文介绍了2018年人工智能大数据的爆发以及学习Java和Python的相关知识。在人工智能和大数据时代,Java和Python这两门编程语言都很优秀且火爆。选择学习哪门语言要根据个人兴趣爱好来决定。Python是一门拥有简洁语法的高级编程语言,容易上手。其特色之一是强制使用空白符作为语句缩进,使得新手可以快速上手。目前,Python在人工智能领域有着广泛的应用。如果对Java、Python或大数据感兴趣,欢迎加入qq群458345782。 ... [详细]
  • 如何实现织梦DedeCms全站伪静态
    本文介绍了如何通过修改织梦DedeCms源代码来实现全站伪静态,以提高管理和SEO效果。全站伪静态可以避免重复URL的问题,同时通过使用mod_rewrite伪静态模块和.htaccess正则表达式,可以更好地适应搜索引擎的需求。文章还提到了一些相关的技术和工具,如Ubuntu、qt编程、tomcat端口、爬虫、php request根目录等。 ... [详细]
author-avatar
花花花
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有